#!/usr/bin/env bash

source ../../lib/shell/common.sh
PORTS=()

function check_iperf3_stress_results() {
    local logs=${1:-""}
    local iperf3_fail_msg=""

    echo -e "\nCheck the iperf3 stress test results."
    if test -n "$logs";then
        if test ! -f $logs;then
            iperf3_fail_msg="Process exception,failed to exec iperf3 test,no such $logs."
        else
            IPERF3_LOG="$(cat $logs)"
        fi
    fi
    for log in $IPERF3_LOG;do
        test ! -f "$log" && { iperf3_fail_msg="${iperf3_fail_msg}failed to get temporary log in $log\n";continue; }
        if test X"$IPERF3_CONNECT_MODE" == X"TCP";then
            if ! cat $log|grep -wq "iperf Done";then
                iperf3_fail_msg="${iperf3_fail_msg}failed to exec iperf3 test,temporary log in $log\n"
            fi
        fi
        echo -e "\n============[iperf3 log start]==================="
        #read
        while read line;do echo "$line";done < $log
        echo -e "============[iperf3 log end]===================\n"
        echo "cleanup $log"
        [ -f "$log" ] && rm -rf "$log"
    done

    [ -n "$logs" -a -f "$logs" ]  && rm -rf "$logs"
    if [ -n "$iperf3_fail_msg" ];then
        echo -e "$iperf3_fail_msg"
        return 1
    else
        return 0
    fi
}

function iperf3_service_setup() {
    local port=$1
    if remote_check_iperf3_service "service" "$port";then
        remote_check_iperf3_service "stop" "$port"
        remote_check_iperf3_service "start" "$port"
    else
        remote_check_iperf3_service "start" "$port"
    fi

    if ps -ef|grep iperf3|grep -w $port >/dev/null 2>&1;then
        kill -9 `ps -ef|grep iperf3|grep -w $port|awk '{print $2}'`
    fi
}

function get_nic_bandwidth() {
    local cur_nic cur_nic_bandwidth

    cur_nic="$(ip a show|grep -w "$1"|awk '{print $NF}')"
    [ -n "$cur_nic" ] && cur_nic_bandwidth="$(ethtool "$cur_nic"|grep Speed|awk -F ":|/s" '{print $2}'|grep -Ewo '[0-9]+[a-zA-Z]+')"
    [ -n "$cur_nic_bandwidth" ] && IPERF3_TRANSMIT_RATE="$cur_nic_bandwidth"
}

function get_all_sut_ip() {
    #exclude ssh interface ip
    local sut_ip=""
    local cur_ip

    for netface in $AVAILABLE_INTERFACE;do
        if ifconfig $netface | grep -wq inet;then
            cur_ip=$(ifconfig $netface | grep -w inet | awk '{print $2}')
            if ! echo "$cur_ip"|grep -E "^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$"> /dev/null 2>&1;then
                echo "warning: The entered ip address $LTS_IP is invalid." && continue
            fi
            sut_ip="${sut_ip}${cur_ip} "
        fi
    done
    if [ -n "$sut_ip" ];then
        echo "sut ip info: $sut_ip"
        export SUT_IPS="$sut_ip"
        return 0
    else
        return 1
    fi
}

function map_sutip_ltsip() {
    local lts_ip="$1"
    local map_sip_lip=""

    if ! get_all_sut_ip;then
        echo "warning: No IP address is configured for any network port except SSH interface ip!"
        return 1
    else
        for sip in $SUT_IPS;do
            for lip in $lts_ip;do
                if ping -I $sip $lip -w5 >/dev/null 2>&1;then
                    map_sip_lip="${map_sip_lip}${sip};${lip} "
                fi
            done
        done
        if [ -n "$map_sip_lip" ];then
            export MAP_SIP_LIP="$map_sip_lip"
            return 0
        else
            echo "warning: No pair of interworking IP addresses was found for SUT and LTS!"
            return 1
        fi
    fi
}

function run_iperf3_stress_test() {
    local log_logpath=${1:-""}
    local cur_sut_ip
    local cur_lts_ip
    local cur_iperf3_log
    local iperf3_fail_msg=""
    local sut_ip=""
    local cur_avail_lts_ip=""

    for _cmd in iperf3 ethtool ip;do check_cmd "$_cmd";done

    echo "Iperf3 stress test satrt......"
    [ -z "$LTS_IPADDRESS" ] && { echo "Error: LTS IP are required, but none are given";exit 1; }
    get_online_use_network_interface && sut_ip="$(ifconfig $ONLINE_NET_FACE|grep -w inet|awk '{print $2}')"

    for lts_ip in $LTS_IPADDRESS;do
        if ! is_ping_pass "$lts_ip";then
            continue
        else
            if ! is_secret_free_login "$lts_ip";then
                continue
            else
                remote_check_firewall_service "$lts_ip" || test_fail
                if ! echo "$cur_avail_lts_ip" |grep -wq "${lts_ip}";then
                    cur_avail_lts_ip="${cur_avail_lts_ip} ${lts_ip}"
                fi
            fi
        fi
    done

    # cur_avail_lts_ip is null,  test failed
    [ -n "$cur_avail_lts_ip" ] || { echo "Error: No lts ip is available for iperf3 stress test!";exit 1; }
    if map_sutip_ltsip "$cur_avail_lts_ip";then
        echo "sut all interfaces to lts all interfaces."
        for map_info in $MAP_SIP_LIP;do
            cur_sut_ip="$(echo $map_info|awk -F ";" '{print $1}')"
            cur_lts_ip="$(echo $map_info|awk -F ";" '{print $2}')"
            get_nic_bandwidth "$cur_sut_ip"
            # Connection mode is TCP and UDP, The default is TCP connection
            if test X"$IPERF3_CONNECT_MODE" == X"TCP";then
                cmd="iperf3 -c $cur_lts_ip -t $IPERF3_RUNTIME -i $IPERF3_INTERVAL -l $IPERF3_TRANSMIT_SIZE -b $IPERF3_TRANSMIT_RATE -B $cur_sut_ip -P $IPERF3_PROCESS_NUM -p $IPERF3_PORT"
            else
                # UDP connection can't set IPERF3_TRANSMIT_SIZE
                cmd="iperf3 -u -c $cur_lts_ip -t $IPERF3_RUNTIME -i $IPERF3_INTERVAL -b $IPERF3_TRANSMIT_RATE -B $cur_sut_ip -P $IPERF3_PROCESS_NUM -p $IPERF3_PORT"
            fi
            cur_iperf3_log="${IPERF3_LOG_PATH}/${cur_sut_ip}_${cur_lts_ip}_${IPERF3_PORT}.iperf3"
            if ! echo "$IPERF3_LOG"|grep -wq "$cur_iperf3_log";then
                IPERF3_LOG="${IPERF3_LOG}${cur_iperf3_log} "
            fi
            PORTS+=($IPERF3_PORT)
            iperf3_service_setup "$IPERF3_PORT"
            run_cmd "$cmd" "$cur_iperf3_log" &
            ((IPERF3_PORT++))
        done
    else
        echo "sut ssh interface to lts all avail interfaces."
        for lts_ip in $cur_avail_lts_ip;do
            if [ -n "$sut_ip" ];then
                get_nic_bandwidth "$sut_ip"
                for s_ip in $sut_ip;do
                    if test X"$IPERF3_CONNECT_MODE" == X"TCP";then
                        cmd="iperf3 -c $lts_ip -t $IPERF3_RUNTIME -i $IPERF3_INTERVAL -l $IPERF3_TRANSMIT_SIZE -b $IPERF3_TRANSMIT_RATE -B $sut_ip -P $IPERF3_PROCESS_NUM -p $IPERF3_PORT"
                    else
                        cmd="iperf3 -u -c $lts_ip -t $IPERF3_RUNTIME -i $IPERF3_INTERVAL -b $IPERF3_TRANSMIT_RATE -B $sut_ip -P $IPERF3_PROCESS_NUM -p $IPERF3_PORT"
                    fi
                    cur_iperf3_log="${IPERF3_LOG_PATH}/${sut_ip}_${lts_ip}_${IPERF3_PORT}.iperf3"
                    if ! echo "$IPERF3_LOG"|grep -wq "$cur_iperf3_log";then
                        IPERF3_LOG="${IPERF3_LOG}${cur_iperf3_log} "
                    fi
                    PORTS+=($IPERF3_PORT)
                    iperf3_service_setup "$IPERF3_PORT"
                    run_cmd "$cmd" "$cur_iperf3_log" &
                    ((IPERF3_PORT++))
                done
            else
                if test X"$IPERF3_CONNECT_MODE" == X"TCP";then
                    cmd="iperf3 -c $lts_ip -t $IPERF3_RUNTIME -i $IPERF3_INTERVAL -l $IPERF3_TRANSMIT_SIZE -b $IPERF3_TRANSMIT_RATE -P $IPERF3_PROCESS_NUM -p $IPERF3_PORT"
                else
                    cmd="iperf3 -u -c $lts_ip -t $IPERF3_RUNTIME -i $IPERF3_INTERVAL -b $IPERF3_TRANSMIT_RATE -P $IPERF3_PROCESS_NUM -p $IPERF3_PORT"
                fi
                cur_iperf3_log="${IPERF3_LOG_PATH}/localhost_${lts_ip}_${IPERF3_PORT}.iperf3"
                if ! echo "$IPERF3_LOG"|grep -wq "$cur_iperf3_log";then
                    IPERF3_LOG="${IPERF3_LOG}${cur_iperf3_log} "
                fi
                PORTS+=($IPERF3_PORT)
                iperf3_service_setup "$IPERF3_PORT"
                run_cmd "$cmd" "$cur_iperf3_log" &
                ((IPERF3_PORT++))
            fi
        done
    fi
    [ -n "$log_logpath" ] && echo "$IPERF3_LOG" > ${log_logpath}
    wait
    for p in ${PORTS[*]};do
        remote_check_iperf3_service "stop" "$p"
    done

    if [ -z "$log_logpath" ];then
        check_iperf3_stress_results && return 0 || return 1
    fi
}
